package com.baranbaygan.downloadmanager.downloadtracker
{
	import com.baranbaygan.downloadmanager.DownloadFile;
	import com.baranbaygan.downloadmanager.DownloadPackage;
	import com.baranbaygan.downloadmanager.DownloadStatus;
	import com.baranbaygan.downloadmanager.events.DownloadPackageEvent;
	import com.baranbaygan.downloadmanager.events.DownloadPackageProgressEvent;
	import com.baranbaygan.downloadmanager.events.DownloadStatusEvent;
	import com.baranbaygan.downloadmanager.events.FileDownloadEvent;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.filesystem.*;
	
	public class DownloadTracker extends EventDispatcher
	{
		/**
		 * This file contains the list of the files being downloaded currently.
		 */
		private var downloadTrackerFile:File;
		/**
		 * This is where the tracker file is.
		 */
		private var fileUrl:String;		
		private var fileStream:FileStream; 
		
		private var defaultTrackerXml:XML = <trackerPackageList />;
		
		public var trackXml:XML;
		
		public function get DownloadPackageList():XML
		{
			return this.trackXml;
		}
		
		public function DownloadTracker(trackerFileUrl:String)
		{
			super(null);
			
			this.downloadTrackerFile = new File(trackerFileUrl);
			
			if(this.downloadTrackerFile.exists)
			{
				this.ReadFileContents();
			}
			else
			{
				this.CreateDefaultTrackerFile();
			}
		}
		
		/**
		 * This file reads the content of the tracker file and puts them into the trackXml property of this class.
		 */ 
		private function ReadFileContents():void
		{
			var stream:FileStream = new FileStream();
			
			try
			{
				stream.open(this.downloadTrackerFile, FileMode.READ);
				trackXml = new XML(stream.readUTFBytes(stream.bytesAvailable));
				
				// This should actually be put into finally clause
				stream.close();
			}
			catch(e:Error)
			{
				
			}
		}
		
		/**
		 * This functions writes the parameter string into the file. Does not append. Replaces the content.
		 */ 
		private function WriteToFile(str:String):void
		{
			var stream:FileStream = new FileStream();
			
			try
			{
				stream.open(this.downloadTrackerFile, FileMode.WRITE);
				stream.writeUTFBytes(str);
				stream.close();
			}
			catch(e:Error)
			{
				
			}
		}
		
		/**
		 * This function creates the tracker file with default XML if it doesn't exist.
		 */ 
		private function CreateDefaultTrackerFile():void
		{
			WriteToFile(this.defaultTrackerXml.toXMLString());
			ReadFileContents();
		}
		
		/* --------------------------------------------------------
		* Protected functions
		-------------------------------------------------------- */
		
		protected function DownloadPackage_Progress(event:DownloadPackageProgressEvent):void
		{
			var file:DownloadFile = event.EventTargetDownloadFile;
			
			this.trackXml.DownloadPackage.(PackageID == event.TargetDownloadPackage.PackageID)[0].BytesCompleted = event.TargetDownloadPackage.BytesCompleted.toString();
			this.trackXml.DownloadPackage.(PackageID == event.TargetDownloadPackage.PackageID)[0].BytesTotal = event.TargetDownloadPackage.BytesTotal.toString();
			this.trackXml.DownloadPackage.(PackageID == event.TargetDownloadPackage.PackageID)[0].Speed = event.TargetDownloadPackage.Speed.toString();
			
			var fileNode:XML = this.trackXml.DownloadPackage.file.(Url == file.Url)[0];
			if(fileNode != null)
			{
				fileNode.CompletedBytes = event.BytesCompleted.toString(); //String(file.CompletedBytes + event.bytesLoaded);
				fileNode.Speed = file.Speed.toString();
				if(fileNode.TotalBytes == "0")
					fileNode.TotalBytes = event.BytesTotal.toString();
			}			
		}
		protected function DownloadPackage_Open(event:DownloadPackageEvent):void
		{
			var file:DownloadFile = event.EventTargetDownloadFile;
			
			var fileNode:XML = this.trackXml.DownloadPackage.file.(Url == file.Url)[0];
			if(fileNode != null)
			{
				fileNode.Status = DownloadStatus.DOWNLOADING;
			}
			
			this.SaveTrackerFile();			
		}
		protected function DownloadPackage_Complete(event:DownloadPackageEvent):void
		{
			var file:DownloadFile = event.EventTargetDownloadFile;

			var fileNode:XML = this.trackXml.DownloadPackage.file.(Url == file.Url)[0];
			if(fileNode != null)
			{
				fileNode.Status = DownloadStatus.COMPLETED;
			}

			this.trackXml.DownloadPackage.(PackageID == event.TargetDownloadPackage.PackageID).Status = DownloadStatus.COMPLETED;

			this.SaveTrackerFile();			
		}

		protected function DownloadFile_Complete(event:FileDownloadEvent):void
		{
			var file:DownloadFile = event.FileObject;
			var downloadPackage:DownloadPackage = event.TargetDownloadPackage;

			var fileNode:XML = this.trackXml.DownloadPackage.(PackageID == downloadPackage.PackageID)[0].file.(Url == file.Url)[0];
			if(fileNode != null)
			{
				fileNode.Status = DownloadStatus.COMPLETED;
			}

			this.SaveTrackerFile();
		}
		
		protected function DownloadPackage_StatusChange(event:DownloadStatusEvent):void
		{
			var dP:DownloadPackage = DownloadPackage(event.target);
			
			var pNode:XML = this.trackXml.DownloadPackage.(PackageID == dP.PackageID)[0];
			
			if(pNode != null)
			{
				pNode.Status = dP.Status;
				
				if(dP.Status == DownloadStatus.PAUSED)
				{
					for each(var fNode:XML in pNode.file)
					{
						fNode.Status = dP.Status;
					}
				}
			}
			
			this.SaveTrackerFile();
		}
		
		/* --------------------------------------------------------
		* Public functions
		-------------------------------------------------------- */
		
		public function PackageAlreadyAdded(id:String):Boolean
		{
			var list:XMLList = this.trackXml.DownloadPackage.(PackageID == id);			
			if(list.length() > 0)
			{
				return true;
			}
			
			return false;
		}		
		
		public function PackageAlreadyDownloading(id:String):Boolean
		{
			var list:XMLList = this.trackXml.DownloadPackage.(PackageID == id && Status != DownloadStatus.COMPLETED);			
			if(list.length() > 0)
			{
				return true;
			}
			
			return false;
		}
		
		public function UrlAlreadyDownloading(url:String):Boolean
		{
			var list:XMLList = this.trackXml.DownloadPackage.file.(Url == url);			
			if(list.length() > 0)
			{
				return true;
			}
			
			return false;
		}
		
		public function SaveTrackerFile():void
		{
			this.WriteToFile(this.trackXml.toXMLString());
		}

		public function AddPackage(dPackage:DownloadPackage):void
		{
			this.trackXml.appendChild(dPackage.GetDownloadPackageXML());
			this.SaveTrackerFile();
		}
		
		public function RemovePackagebyID(packageId:String):void
		{
			delete this.trackXml.DownloadPackage.(PackageID == packageId)[0];
			this.SaveTrackerFile();
		}

		public function RemovePackage(p:DownloadPackage):void
		{
			delete this.trackXml.DownloadPackage.(PackageID == p.PackageID)[0];
			
			clearEventListeners(p);

			this.SaveTrackerFile();
		}

		public function configureDownloadPackageListeners(obj:EventDispatcher):void
		{ 
			// obj is DownloadPackage
			
			obj.addEventListener(DownloadPackageProgressEvent.DownloadPackageProgress, DownloadPackage_Progress);
			obj.addEventListener(Event.OPEN, DownloadPackage_Open);
			obj.addEventListener(Event.COMPLETE, DownloadPackage_Complete);
			obj.addEventListener(FileDownloadEvent.FILE_COMPLETE, DownloadFile_Complete);
			obj.addEventListener(DownloadStatusEvent.StatusChange, DownloadPackage_StatusChange);
			
			//obj.addEventListener(ProgressEvent.PROGRESS, UpdateFileProgress);			
			//obj.addEventListener(Event.OPEN, OpenFileDownload);
			//obj.addEventListener(Event.COMPLETE, FileDownloadComplete);
		}
		
		private function clearEventListeners(obj:EventDispatcher):void
		{
			obj.removeEventListener(DownloadPackageProgressEvent.DownloadPackageProgress, DownloadPackage_Progress);
			obj.removeEventListener(Event.OPEN, DownloadPackage_Open);
			obj.removeEventListener(Event.COMPLETE, DownloadPackage_Complete);
			obj.removeEventListener(FileDownloadEvent.FILE_COMPLETE, DownloadFile_Complete);
			obj.removeEventListener(DownloadStatusEvent.StatusChange, DownloadPackage_StatusChange);
		}
		
	}
}